refactor(db): dedupe Z.AI migrations, account row mapping, emoji query (#1135) - #1284
Conversation
#1135) migrations.py: the twin Z.AI base_url rewriters (_migrate_zai_legacy_base_url and _migrate_zai_empty_base_url_to_coding) shared an identical load-JSON / walk-zai-items / save-on-change body. Extracted _rewrite_zai_base_urls taking a should_rewrite predicate + target URL; each public migration is now a thin caller. Both run only when something changed (unchanged), and each keeps its own provider_registry import + log message. accounts.py: the Account(...) constructor block was duplicated verbatim in get_accounts and get_live_usable_accounts. Extracted _account_from_row(row, session_string); the two methods differ only in how they handle a decrypt failure (raise vs skip), which stays in the caller. get_decrypted_session reimplemented as a delegate to get_session_export so the SELECT + decrypt + row-binding (#1145 consistency) is no longer forked. messages.py: get_trending_emojis had two near-identical SQL bodies differing only by a collected_at window fragment. Collapsed into one query with an optional WHERE fragment + parameterized params list. All three jscpd clones from the #1135 target list are removed. migrations/accounts/messages unit + repository tests pass (400 + 481). Part of #1135 (axis 5 of #1130). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
7fdfd7f to
bb01b21
Compare
🔍 Local review — cycle 1/3 (clean)Reviewed locally via built-in Three MOVE/extraction refactors — both reviewers confirmed semantic equivalence of each:
Notable: No Tests: Totals: 0 FIX, 0 SKIP, 0 UNVERIFIED. Review cycle complete — merge is yours to trigger (local mode does not auto-merge). |
Part of #1135 (axis 5 of #1130). Three clones from the #1135 target list, all genuine duplication (no parity surface involved).
What & how
migrations.py— twin Z.AI base_url rewriters_migrate_zai_legacy_base_urland_migrate_zai_empty_base_url_to_codingshared an identical load-JSON → walk zai items → save-on-change body (21-line clone, 109 tokens). Extracted_rewrite_zai_base_urls(db, *, should_rewrite, new_base_url, log_message). Each public migration is now a thin caller passing its own predicate + target URL.provider_registryimport + distinct log message.accounts.py— duplicated Account row mapping + forked SELECTAccount(...)constructor block was verbatim inget_accountsandget_live_usable_accounts. Extracted_account_from_row(row, session_string); the two methods differ only in decrypt-failure handling (raise vs skip), which stays in the caller.get_decrypted_sessionreimplemented the SELECT-by-id/phone + decrypt. It now delegates toget_session_export, so the row-binding consistency guard (REST: POST /api/accounts/{id}/export-session #1145) — phone and session bound to the same row read — is no longer forked. Returnsexported[1](the session).messages.py—get_trending_emojisTwo near-identical SQL bodies differing only by a
collected_atwindow fragment. Collapsed into one query with an optionalWHEREfragment + parameterizedparamslist.Verification
tests/test_migrations.py+tests/repositories/(400) green.jscpd
All three clones from the #1135 target list (
migrations.py:720↔762,accounts.pytwo pairs,messages.py) are removed.Part of #1135 / #1130. Not for merge — review requested.
🤖 Generated with Claude Code